﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using BookingDB.Models;
using GenericModels;

namespace CTRLayer
{
    public class CTRSeat
    {
        private BioBookingContext db;

        public CTRSeat()
        {
            db = new BioBookingContext();
        }

        /// <summary>
        /// Retrieves a single seat from the database, based on the unique seat identifier
        /// </summary>
        /// <param name="seatId"></param>
        /// <returns>A Seat</returns>
        public Seat GetSeat(int seatId)
        {
            EntitySeat eSeat = (from e in db.Seats
                                where e.id == seatId
                                select e).SingleOrDefault();
            
            return TranslateSeat(eSeat);
        }

        /// <summary>
        /// Retrieves all the seats connected to a single show
        /// </summary>
        /// <param name="show"></param>
        /// <returns>A list containing all seats on a single show</returns>
        public List<Seat> GetAllSeatsOnShow(Show show)
        {
            List<Seat> allTheSeats = new List<Seat>();

            IQueryable<EntitySeat> eSeats = (from s in db.Seats
                                             where s.show_id == show.Show_Id
                                             select s);


            foreach (EntitySeat es in eSeats)
            {
                allTheSeats.Add(TranslateSeat(es));
            }

            return allTheSeats;

        }

        /// <summary>
        /// Finds the desired seat, based on the seat id, and checking that the current status of said seat is 0.
        /// If the status of the seat is not 0, then it has been booked by another, and so the transaction must fail
        /// in order to secure atomicity.
        /// For this purpose we employ the TransactionScope class, and sets the IsolationLevel to snapshot.  
        /// </summary>
        /// <param name="seat"></param>
        /// <param name="status"></param>
        /// <returns>An integer value</returns>
        public int LockSeat(List<Seat> seats, int status)
        {

            int result = -1;

            //
            using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions
                {
                    IsolationLevel = IsolationLevel.Snapshot
                }))
            {
                using (var context = new BioBookingContext())
                {
                    foreach (Seat s in seats)
                    {
                        try
                        {
                            EntitySeat eSeat = (from es in db.Seats
                                                where es.id == s.SeatId && es.status == "0"   
                                                select es).First();

                            eSeat.status = status.ToString();
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("Error: " + e);
                        }
                    }
                    result = db.SaveChanges();
                }
                scope.Complete();
            }

            

            return result;
        }

        /// <summary>
        /// Finds the desired seat, based on the seat id. Then updates the status of this seat to 0
        /// which means unlocked, and returns a boolean value if succesful
        /// </summary>
        /// <param name="seat"></param>
        /// <returns></returns>
        public bool UnLockSeat(Seat seat)
        {
            bool unlocked = false;
            EntitySeat eSeat = (from s in db.Seats
                                    where s.id == seat.SeatId
                                    select s).SingleOrDefault();
            eSeat.status = "0";
            
            try
            {
                db.SaveChanges();
                unlocked = true;
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e);
            }
            return unlocked;
        }


        #region Translated method
        /// <summary>
        /// Helper method which translates the retrieved entity framework object into a generic model
        /// </summary>
        /// <param name="eSeat"></param>
        /// <returns>A Seat</returns>
        public Seat TranslateSeat(EntitySeat eSeat)
        {
            Seat s = new Seat();

            s.SeatId = eSeat.id;
            s.Show_Id = (int)eSeat.show_id;
            s.Status = eSeat.status;

            return s;
        }
        #endregion
    }
}
